﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Djs.Tools.XmlPersistor;
using System.Drawing;

namespace Noris.Tools.TraceVisualiser.Support
{
    /// <summary>
    /// Konfigurace aplikace
    /// </summary>
    public class Config : IXmlPersistNotify
    {
        public Config()
        {
            this.LastProjectPath = "";
            this.LastTracePath = "";
            this.LastProjects = new List<string>();
			this.LastProjectsCount = 5;
            this.SearchItemsCount = 250;
            this.DocSimpleEnabled = true;
            this.DocAutosaveEnabled = true;
            this.DocOpenLastEnabled = true;
            this.FormClosingQuery = true;
            this.TraceAutoTimeShift = true;
            this.BackgroundMode = MainBackgroundMode.InternalTile;
        }
        #region Property
        /// <summary>
        /// Soubor s daty Configu
        /// </summary>
        [PersistingEnabled(false)]
        public string ConfigFile { get; private set; }
        /// <summary>
        /// Posledně použitá cesta k projektům
        /// </summary>
        public string LastProjectPath { get; set; }
        /// <summary>
        /// Posledně použitá cesta k trace souborům
        /// </summary>
        public string LastTracePath { get; set; }
        /// <summary>
        /// Posledně použitá cesta pro Export/Import konfiguračních a dalších souborů
        /// </summary>
        public string LastExportImportPath { get; set; }
        /// <summary>
        /// Několik nedávných projektů, první v seznamu je nejnovější (aktuální se vkládá na pozici 0, z poslední pozice vypadávají nejstarší záznamy)
        /// </summary>
        public List<string> LastProjects { get; set; }
		/// <summary>
		/// Maximální počet položek RecentFiles (0 - 24).
		/// Při hodnotě 0 se RecentFiles nenabízejí.
		/// Při hodnotě 1 - 7 se RecentFiles nabízejí přímo v menu Soubory.
		/// Při hodnotě 8 a více se RecentFiles zobrazují v submenu Nedávné projekty v menu Soubory.
		/// Rozhoduje hodnota LastProjectsCount, ne počet položek v poli LastProjects.
		/// </summary>
		public int LastProjectsCount { get; set; }
        /// <summary>
        /// Počet událostí, po jejichž nalezení dojde k pozastavení vyhledávače.
        /// </summary>
        public int SearchItemsCount { get; set; }
        /// <summary>
        /// Je povoleno zobrazování zjednodušeného zadání projektu
        /// </summary>
        public bool DocSimpleEnabled { get; set; }
        /// <summary>
        /// Je povoleno automatické ukládání projektu
        /// </summary>
        public bool DocAutosaveEnabled { get; set; }
        /// <summary>
        /// Je povoleno při startu aplikace otevírat ty projekty, které byly otevřeny při posledním zavření
        /// </summary>
        public bool DocOpenLastEnabled { get; set; }
        /// <summary>
        /// Režim práce s pozadím MainForm
        /// </summary>
        public MainBackgroundMode BackgroundMode { get; set; }
        /// <summary>
        /// Barva pozadí plochy MainForm
        /// </summary>
        public Color BackgroundColor { get; set; }
        /// <summary>
        /// Obrázek na pozadí plochy MainForm
        /// </summary>
        public string BackgroundImageFile { get; set; }
        /// <summary>
        /// Příznak, zda při zavírání aplikace (pokud jsou načteny nějaké projekty) se má zobrazit dotaz
        /// </summary>
        public bool FormClosingQuery { get; set; }
        /// <summary>
        /// Příznak, zda se má automaticky detekovat časový posun klientského trace proti serveru
        /// </summary>
        public bool TraceAutoTimeShift { get; set; }
        /// <summary>
        /// Režim práce s pozadím MainForm
        /// </summary>
        public enum MainBackgroundMode
        {
            None = 0,
            StandardWindows,
            StandardTraceAnalyser,
            FullColor,
            ImageTile,
            ImageCenter,
            InternalTile
        }
        /// <summary>
        /// Pole custom barev do dialogu ColorDialog
        /// </summary>
        [PersistingEnabled(false)]
        public int[] CustomColors { get; set; }
        /// <summary>
        /// Privátní kopie pole barev CustomColors, slouží pouze pro persistenci
        /// </summary>
        [PropertyName("CustomColors")]
        private List<int> _CustomColors
        {
            get { if (CustomColors == null) return null; return new List<int>(CustomColors); }
            set { if (value != null) CustomColors = value.ToArray(); }
        }
        #endregion
        #region Klonování
        /// <summary>
        /// Izolovaný klon. Slouží pro předání dat k editace a k převzetí editovaných dat do sebe po editaci.
        /// </summary>
        [PersistingEnabled(false)]
        public Config Clone
        {
            get { return this._GetClone(); }
            set { this._SetClone(value); }
        }
        private Config _GetClone()
        {
            Config clone = (Config)this.MemberwiseClone();
            if (this.CustomColors != null)
                clone.CustomColors = this.CustomColors.ToArray();
            if (this.LastProjects != null)
                clone.LastProjects = new List<string>(this.LastProjects);
            return clone;
        }
        private void _SetClone(Config value)
        {
            if (value == null) return;

            Persist.CloneTo(value, this);

            //this.BackgroundColor = value.BackgroundColor;
            //this.BackgroundImageFile = value.BackgroundImageFile;
            //this.BackgroundMode = value.BackgroundMode;
            //this.CustomColors = (value.CustomColors == null ? null : value.CustomColors.ToArray());
            //this.DocAutosaveEnabled = value.DocAutosaveEnabled;
            //this.DocOpenLastEnabled = value.DocOpenLastEnabled;
            //this.DocSimpleEnabled = value.DocSimpleEnabled;
            //this.LastExportImportPath = value.LastExportImportPath;
            //this.LastProjectPath = value.LastProjectPath;
            //this = value;
        }
        #endregion
        #region Last projects metody pro údržbu
        /// <summary>
		/// Přidá do this.LastProjects zadaný projectFile.
		/// </summary>
		/// <param name="projectFile"></param>
		/// <returns></returns>
		internal bool LastProjectsAdd(string projectFile)
		{
			if (this.LastProjects == null)
				this.LastProjects = new List<string>();
			if (String.IsNullOrEmpty(projectFile)) return false;

			if (this.LastProjectsCount == 0) return false;

			// Podíváme se, zda daný soubor už někde máme:
			int findIdx = this.LastProjects.FindIndex(f => String.Equals(f, projectFile, StringComparison.OrdinalIgnoreCase));
			if (findIdx == 0)
			{	// Pokud najdu soubor na pozici 0, nebudu s ním nic dělat. Vlastně: mohl bych jej aktualizovat (rozdíly v upper/lower case):
				this.LastProjects[0] = projectFile;
			}
			else
			{	// Soubor v seznamu již je? Pak je na pozici != 0, tak ho z ní odeberu:
				if (findIdx > 0)
					this.LastProjects.RemoveAt(findIdx);
				// Soubor vložím na pozici 0:
				if (this.LastProjects.Count == 0)
					this.LastProjects.Add(projectFile);
				else
					this.LastProjects.Insert(0, projectFile);
			}

			// Údržba délky seznamu:
			this.LastProjectsTrim();

            // AutoSave:
            this.Save();

			return true;
		}
		/// <summary>
		/// Pokud eviduje daný soubor v poli RecentProjectFiles, pak jej tam odsud odebere.
		/// </summary>
		/// <param name="projectFile"></param>
		public bool LastProjectRemove(string projectFile)
		{
			if (this.LastProjects == null)
				this.LastProjects = new List<string>();
			if (String.IsNullOrEmpty(projectFile)) return false;

			// Podíváme se, zda daný soubor už někde máme:
			int findIdx = this.LastProjects.FindIndex(f => String.Equals(f, projectFile, StringComparison.OrdinalIgnoreCase));
			if (findIdx >= 0)
			{	// Pokud najdu soubor, odeberu jej:
				this.LastProjects.RemoveAt(findIdx);
                
                // AutoSave:
                this.Save();

                return true;
			}
			return false;
		}
		/// <summary>
		/// Vyprázdní pole this.LastProjects
		/// </summary>
		public void LastProjectsClear()
		{
			if (this.LastProjects == null)
				this.LastProjects = new List<string>();
			else
				this.LastProjects.Clear();
		}
		/// <summary>
		/// Zajistí, že pole this.LastProjects nebude mít více prvků, než je povoleno v this.LastProjectsCount
		/// </summary>
		public void LastProjectsTrim()
		{
			if (this.LastProjects == null)
				this.LastProjects = new List<string>();

			int maxCount = this.LastProjectsCount;
			if (maxCount < 0) maxCount = 0;
			int currentCount = this.LastProjects.Count;
			if (currentCount > maxCount)
				this.LastProjects.RemoveRange(maxCount, currentCount - maxCount);
		}
        #endregion
        #region Persistence
        /// <summary>
        /// Načte do sebe konfiguraci
        /// </summary>
        internal void Load(string configFile)
        {
            this.ConfigFile = configFile;
			// Defaultní hodnoty:
            this.LastProjectPath = Steward.MainExePath;
            this.LastTracePath = Steward.MainExePath;
            this.LastProjects = new List<string>();

			// Načíst XML:
			if (!String.IsNullOrEmpty(configFile) && System.IO.File.Exists(configFile))
			{
				PersistArgs args = PersistArgs.Default;
				args.XmlFile = configFile;
				Persist.LoadTo(args, this);
			}
        }
        /// <summary>
		/// Metoda, kterou vyvolá událost dokončení XML load, 
		/// pomocí změny stavu property IXmlPersistNotify.XmlPersistState na stav LoadDone.
        /// </summary>
        private void _LoadAfter()
        {
            Dictionary<string, object> files = new Dictionary<string,object>();
            if (this.LastProjects != null)
            {
                foreach (string file in this.LastProjects)
                {
                    if (!String.IsNullOrEmpty(file) && !files.ContainsKey(file))
                        files.Add(file, null);
                }
            }
            this.LastProjects = new List<string>(files.Keys);
        }
        /// <summary>
        /// Uloží konfig do svého souboru
        /// </summary>
        public void Save()
        {
            if (!String.IsNullOrEmpty(this.ConfigFile))
            {
                PersistArgs arg = PersistArgs.Default;
                arg.WriterSettings.NewLineHandling = System.Xml.NewLineHandling.Entitize;
                arg.WriterSettings.NewLineOnAttributes = true;
				arg.XmlFile = this.ConfigFile;     // Persist zajistí i korektní uložení do souboru v UTF-8, včetně vytvoření adresáře.
                Persist.Serialize(this, arg);
            }
        }
        #endregion
        #region IXmlPersistNotify Members
        /// <summary>
        /// interface IXmlPersistNotify : dává objektu možnost být informován o procesech XmlPersist (Save / Load) pomocí obsluhy set accessoru property XmlPersistState.
        /// Jakýkoli objekt, který chce být informován o tom, že je ukládán do XML / obnovován z XML, musí deklarovat interface IXmlPersistNotify.
        /// Pak do jeho property IXmlPersistNotify.XmlPersistState bude vkládána hodnota: při ukládání do XML hodnota Save (a po dokončení None), při načítání z XML hodnota Load a None.
        /// </summary>
        [PersistingEnabled(false)]
        XmlPersistState IXmlPersistNotify.XmlPersistState
        {
            get
            {
                return this._XmlPersistState;
            }
            set
            {
                this._XmlPersistState = value;
                switch (value)
                {
                    case XmlPersistState.LoadDone:
                        this._LoadAfter();
                        break;
                }
            }
        }
        /// <summary>
        /// Proměnná, která obsahuje aktuální stav objektu z hlediska XML persistence.
        /// </summary>
        private XmlPersistState _XmlPersistState;
        #endregion
    }
}
